package com.hx.zhg.util;


import com.hx.zhg.constant.CommonConstant;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Map;

/**
 * http工具类
 */
public class HttpClientUtil {

    private static final Logger log = LoggerFactory.getLogger(HttpClientUtil.class);
    private static final String HTTP_SCHEMA = "http";
    private static final String HTTPS_SCHEMA = "https";
    private static final String SSL_INSTANCE = "TLS";
    private static volatile PoolingHttpClientConnectionManager cm = null;
    private static volatile PoolingHttpClientConnectionManager sslCm = null;

    static {
        cm = new PoolingHttpClientConnectionManager();
        cm.setMaxTotal(20);
        cm.setDefaultMaxPerRoute(5);
        // ssl registry和配置
        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register(HTTPS_SCHEMA, createSSLConnSocketFactory()).build();
        sslCm = new PoolingHttpClientConnectionManager(registry);
        sslCm.setMaxTotal(20);
        sslCm.setDefaultMaxPerRoute(5);
    }

    /**
     * get方式进行http访问
     *
     * @param url 访问地址
     * @return
     */
    public static String doHttpGetRequest(String url) {
        HttpGet httpGet = new HttpGet(url);
        return execute(httpGet, HTTP_SCHEMA);
    }

    /**
     * get方式进行https访问
     *
     * @param url 访问地址
     * @return
     */
    public static String doHttpsGetRequest(String url) {
        HttpGet httpGet = new HttpGet(url);
        return execute(httpGet, HTTPS_SCHEMA);
    }

    /**
     * get方式进行https访问
     *
     * @param url 访问地址
     * @return
     */
    public static String doHttpsGetRequestURL(String url) throws Exception {
        URL url1 = new URL(url);
        URI uri = new URI(url1.getProtocol(), url1.getHost(), url1.getPath(), url1.getQuery(), null);
        HttpGet httpGet = new HttpGet(uri);
        return execute(httpGet, HTTPS_SCHEMA);
    }

    /**
     * get方式进行http访问
     *
     * @param url    访问地址
     * @param params 参数
     * @return
     * @throws URISyntaxException
     */
    public static String doHttpGetRequest(String url, Map<String, Object> params) throws URISyntaxException {
        URIBuilder ub = new URIBuilder();
        ub.setPath(url);

        ArrayList<NameValuePair> pairs = mapToNameValuePairs(params);
        ub.setParameters(pairs);

        HttpGet httpGet = new HttpGet(ub.build());
        return execute(httpGet, HTTP_SCHEMA);
    }

    /**
     * get方式进行https访问
     *
     * @param url    访问地址
     * @param params 参数
     * @return
     * @throws URISyntaxException
     */
    public static String doHttpsGetRequest(String url, Map<String, Object> params) throws URISyntaxException {
        URIBuilder ub = new URIBuilder();
        ub.setPath(url);

        ArrayList<NameValuePair> pairs = mapToNameValuePairs(params);
        ub.setParameters(pairs);

        HttpGet httpGet = new HttpGet(ub.build());
        return execute(httpGet, HTTPS_SCHEMA);
    }

    /**
     * get方式进行http访问
     *
     * @param url     访问地址
     * @param headers 请求头参数
     * @param params  参数
     * @return
     * @throws URISyntaxException
     */
    public static String doHttpGetRequest(String url, Map<String, Object> headers, Map<String, Object> params)
            throws URISyntaxException {
        URIBuilder ub = new URIBuilder();
        ub.setPath(url);

        ArrayList<NameValuePair> pairs = mapToNameValuePairs(params);
        ub.setParameters(pairs);

        HttpGet httpGet = new HttpGet(ub.build());
        for (Map.Entry<String, Object> param : headers.entrySet()) {
            httpGet.addHeader(param.getKey(), String.valueOf(param.getValue()));
        }
        return execute(httpGet, HTTP_SCHEMA);
    }

    /**
     * get方式进行https访问
     *
     * @param url     访问地址
     * @param headers 请求头参数
     * @param params  参数
     * @return
     * @throws URISyntaxException
     */
    public static String doHttpsGetRequest(String url, Map<String, Object> headers, Map<String, Object> params)
            throws URISyntaxException {
        URIBuilder ub = new URIBuilder();
        ub.setPath(url);

        ArrayList<NameValuePair> pairs = mapToNameValuePairs(params);
        ub.setParameters(pairs);

        HttpGet httpGet = new HttpGet(ub.build());
        for (Map.Entry<String, Object> param : headers.entrySet()) {
            httpGet.addHeader(param.getKey(), String.valueOf(param.getValue()));
        }
        return execute(httpGet, HTTPS_SCHEMA);
    }

    /**
     * post方式进行http访问
     *
     * @param url 访问地址
     * @return
     */
    public static String doHttpPostRequest(String url) {
        HttpPost httpPost = new HttpPost(url);
        return execute(httpPost, HTTP_SCHEMA);
    }

    /**
     * post方式进行https访问
     *
     * @param url 访问地址
     * @return
     */
    public static String doHttpsPostRequest(String url) {
        HttpPost httpPost = new HttpPost(url);
        return execute(httpPost, HTTPS_SCHEMA);
    }

    /**
     * post方式http访问
     *
     * @param url    访问地址
     * @param params 参数
     * @return
     * @throws URISyntaxException
     */
    public static String doHttpPostRequest(String url, Map<String, Object> params) throws UnsupportedEncodingException {
        HttpPost httpPost = new HttpPost(url);
        ArrayList<NameValuePair> pairs = mapToNameValuePairs(params);
        httpPost.setEntity(new UrlEncodedFormEntity(pairs, CommonConstant.CHARSET_UTF_8));
        return execute(httpPost, HTTP_SCHEMA);
    }

    /**
     * post方式https访问
     *
     * @param url    访问地址
     * @param params 参数
     * @return
     * @throws URISyntaxException
     */
    public static String doHttpsPostRequest(String url, Map<String, Object> params) throws UnsupportedEncodingException {
        HttpPost httpPost = new HttpPost(url);
        ArrayList<NameValuePair> pairs = mapToNameValuePairs(params);
        httpPost.setEntity(new UrlEncodedFormEntity(pairs, CommonConstant.CHARSET_UTF_8));
        return execute(httpPost, HTTPS_SCHEMA);
    }

    /**
     * post方式进行http访问
     *
     * @param url     访问地址
     * @param headers 请求头参数
     * @param params  参数
     * @return
     * @throws URISyntaxException
     */
    public static String doHttpPostRequest(String url, Map<String, Object> headers, Map<String, Object> params)
            throws UnsupportedEncodingException {
        HttpPost httpPost = new HttpPost(url);

        for (Map.Entry<String, Object> param : headers.entrySet()) {
            httpPost.addHeader(param.getKey(), String.valueOf(param.getValue()));
        }

        ArrayList<NameValuePair> pairs = mapToNameValuePairs(params);
        httpPost.setEntity(new UrlEncodedFormEntity(pairs, CommonConstant.CHARSET_UTF_8));

        return execute(httpPost, HTTP_SCHEMA);
    }

    /**
     * post方式进行https访问
     *
     * @param url     访问地址
     * @param headers 请求头参数
     * @param params  参数
     * @return
     * @throws URISyntaxException
     */
    public static String doHttpsPostRequest(String url, Map<String, Object> headers, Map<String, Object> params)
            throws UnsupportedEncodingException {
        HttpPost httpPost = new HttpPost(url);

        for (Map.Entry<String, Object> param : headers.entrySet()) {
            httpPost.addHeader(param.getKey(), String.valueOf(param.getValue()));
        }

        ArrayList<NameValuePair> pairs = mapToNameValuePairs(params);
        httpPost.setEntity(new UrlEncodedFormEntity(pairs, CommonConstant.CHARSET_UTF_8));

        return execute(httpPost, HTTPS_SCHEMA);
    }


    /*
     * map参数转换为NameValuePair对
     */
    private static ArrayList<NameValuePair> mapToNameValuePairs(Map<String, Object> params) {
        ArrayList<NameValuePair> pairs = new ArrayList<NameValuePair>();
        for (Map.Entry<String, Object> param : params.entrySet()) {
            pairs.add(new BasicNameValuePair(param.getKey(), String.valueOf(param.getValue())));
        }

        return pairs;
    }

    /**
     * 处理Http请求
     *
     * @param request
     * @param scheme  http或者https
     * @return
     */
    private static String execute(HttpRequestBase request, String scheme) {
        scheme = StringUtils.trim(scheme);
        CloseableHttpClient httpClient = HTTPS_SCHEMA.equalsIgnoreCase(scheme) ? getHttpsClient() : getHttpClient();
        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(request);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                String result = EntityUtils.toString(entity);
                return result;
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
        return StringUtils.EMPTY;
    }

    /**
     * 创建SSL安全连接
     *
     * @return
     */
    private static SSLConnectionSocketFactory createSSLConnSocketFactory() {
        X509TrustManager tm = new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] chain,
                                           String authType) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain,
                                           String authType) throws CertificateException {
            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        SSLContext sslContext = null;
        try {
            sslContext = SSLContext.getInstance(SSL_INSTANCE);
            sslContext.init(null, new TrustManager[]{tm}, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
        SSLConnectionSocketFactory sslConnectionFactory = new SSLConnectionSocketFactory(sslContext,
                SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
        return sslConnectionFactory;
    }

    /*
     * 获取HttpClient
     *
     * @return
     */
    private static CloseableHttpClient getHttpClient() {
        return HttpClients.custom().setConnectionManager(cm).build();
    }

    /*
     * 获取HttpsClient
     *
     * @return
     */
    private static CloseableHttpClient getHttpsClient() {
        return HttpClients.custom().setConnectionManager(sslCm).build();
    }


}
